package cn.ciis.basic.kit;

import net.oschina.j2cache.CacheChannel;
import net.oschina.j2cache.CacheObject;
import net.oschina.j2cache.CacheProvider;

import java.util.Collection;
import java.util.Map;
import java.util.function.Function;

public class J2CacheKit {

    private static CacheChannel cache;

    public static void init(CacheChannel cache) {
        J2CacheKit.cache = cache;
    }


    /**
     * 读取缓存（用户无需判断返回的对象是否为空）
     * @param region Cache region name
     * @param key Cache data key
     * @param cacheNullObject 是否缓存空对象
     * @return cache object
     */
    public static CacheObject get(String region, String key, boolean...cacheNullObject)  {

       return cache.get(region,key,cacheNullObject);
    }

    /**
     * 支持外部数据自动加载的缓存方法
     * @param region Cache region name
     * @param key Cache data key
     * @param loader data loader
     * @param cacheNullObject  true if you need to cache null object
     * @return cache object
     */
    public static CacheObject get(String region, String key, Function<String, Object> loader, boolean...cacheNullObject) {

        return cache.get(region, key, loader, cacheNullObject);
    }

    /**
     * 批量读取缓存中的对象（用户无需判断返回的对象是否为空）
     * @param region Cache region name
     * @param keys cache keys
     * @return cache object
     */
    public static Map<String, CacheObject> get(String region, Collection<String> keys)  {

        return  cache.get(region, keys);
    }

    /**
     * 使用数据加载器的批量缓存读取
     * @param region Cache region name
     * @param keys cache keys
     * @param loader data loader
     * @param cacheNullObject true if you need to cache null object
     * @return multiple cache data
     */
    public static Map<String, CacheObject> get(String region, Collection<String> keys, Function<String, Object> loader, boolean...cacheNullObject)  {

        return cache.get(region, keys, loader, cacheNullObject);
    }

    /**
     * 判断某个缓存键是否存在
     * @param region Cache region name
     * @param key cache key
     * @return true if key exists
     */
    public static boolean exists(String region, String key) {
        return check(region, key) > 0;
    }

    /**
     * 判断某个key存在于哪级的缓存中
     * @param region cache region
     * @param key cache key
     * @return  0(不存在),1(一级),2(二级)
     */
    public static int check(String region, String key) {
        return cache.check(region, key);
    }

    /**
     * Write data to J2Cache
     *
     * @param region: Cache Region name
     * @param key: Cache key
     * @param value: Cache value
     */
    public static void set(String region, String key, Object value) {

        cache.set(region, key, value);
    }

    /**
     * Write data to J2Cache
     *
     * @param region: Cache Region name
     * @param key: Cache key
     * @param value: Cache value
     * @param cacheNullObject if allow cache null object
     */
    public static void set(String region, String key, Object value, boolean cacheNullObject) {

        cache.set(region, key, value, cacheNullObject);
    }


    /**
     * Write data to j2cache with expired setting
     *
     * <strong>注意：强烈不推荐使用带 TTL 的 set 方法，所有的缓存 TTL 都应该预先配置好，避免多个节点的缓存 Region 配置不同步</strong>
     *
     * @param region Cache Region name
     * @param key Cache Key
     * @param value Cache value
     * @param timeToLiveInSeconds cache expired in second
     */
    public static void set(String region, String key, Object value, long timeToLiveInSeconds ) {
        cache.set(region, key, value, timeToLiveInSeconds);
    }

    /**
     * Write data to j2cache with expired setting
     *
     * <strong>注意：强烈不推荐使用带 TTL 的 set 方法，所有的缓存 TTL 都应该预先配置好，避免多个节点的缓存 Region 配置不同步</strong>
     *
     * @param region Cache Region name
     * @param key Cache Key
     * @param value Cache value
     * @param timeToLiveInSeconds cache expired in second
     * @param cacheNullObject if allow cache null object
     */
    public static void set(String region, String key, Object value, long timeToLiveInSeconds, boolean cacheNullObject) {

        cache.set(region, key, value, timeToLiveInSeconds, cacheNullObject);
    }

    /**
     * 批量插入数据
     * @param region Cache Region name
     * @param elements Cache Elements
     */
    public static void set(String region, Map<String, Object> elements){
        cache.set(region, elements);
    }

    /**
     * 批量插入数据
     * @param region Cache Region name
     * @param elements Cache Elements
     * @param cacheNullObject if allow cache null object
     */
    public static void set(String region, Map<String, Object> elements, boolean cacheNullObject)  {

        cache.set(region, elements, cacheNullObject);
    }

    /**
     * 带失效时间的批量缓存数据插入
     *
     * <strong>注意：强烈不推荐使用带 TTL 的 set 方法，所有的缓存 TTL 都应该预先配置好，避免多个节点的缓存 Region 配置不同步</strong>
     *
     * @param region Cache Region name
     * @param elements Cache Elements
     * @param timeToLiveInSeconds cache expired in second
     */
    public static void set(String region, Map<String, Object> elements, long timeToLiveInSeconds){
        cache.set(region, elements, timeToLiveInSeconds);
    }

    /**
     * 带失效时间的批量缓存数据插入
     *
     * <strong>注意：强烈不推荐使用带 TTL 的 set 方法，所有的缓存 TTL 都应该预先配置好，避免多个节点的缓存 Region 配置不同步</strong>
     *
     * @param region Cache Region name
     * @param elements Cache Elements
     * @param timeToLiveInSeconds cache expired in second
     * @param cacheNullObject if allow cache null object
     */
    public static void set(String region, Map<String, Object> elements, long timeToLiveInSeconds, boolean cacheNullObject)  {

        cache.set(region, elements, timeToLiveInSeconds, cacheNullObject);
    }

    /**
     * Remove cached data in J2Cache
     *
     * @param region:  Cache Region name
     * @param keys: Cache key
     */
    public static void evict(String region, String...keys)  {

        cache.evict(region, keys);
    }

    /**
     * Clear the cache
     *
     * @param region: Cache region name
     */
    public static void clear(String region)  {

        cache.clear(region);
    }

    /**
     * 返回所有的缓存区域
     * @return all the regions
     */
    public static Collection<CacheChannel.Region> regions() {
        return cache.regions();
    }

    /**
     * 删除缓存 Region
     * @param region Cache Region Name
     */
    public static void removeRegion(String region) {
        cache.removeRegion(region);
    }

    /**
     * <p>Get cache region keys</p>
     * <p><strong>Notice: ehcache3 not support keys</strong></p>
     *
     * @param region: Cache region name
     * @return key list
     */
    public static Collection<String> keys(String region)  {

        return cache.keys(region);
    }

    /**
     * Close J2Cache
     */

    public static void close() {
        cache.close();
    }

    /**
     * 获取一级缓存接口
     * @return 返回一级缓存的 CacheProvider 实例
     */
    public static CacheProvider getL1Provider() {
        return cache.getL1Provider();
    }

    /**
     * <p>获取二级缓存的接口，该方法可用来直接获取 J2Cache 底层的 Redis 客户端实例</p>
     * <p>方法如下：</p>
     * <code>
     *     CacheChannel channel = J2Cache.getChannel();
     *     RedisClient client = ((RedisCacheProvider)channel.getL2Provider()).getRedisClient();
     *     try {
     *     	   client.get().xxxxx(...);
     *     } finally {
     *         client.release();
     *     }
     * </code>
     * @return 返回二级缓存的 CacheProvider 实例
     */
    public static CacheProvider getL2Provider() {
        return cache.getL2Provider();
    }
}
